/*
    gntparted - a GNT-frontend to libparted
    Copyright (C) 2007
    Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
    Free Software Foundation, Inc.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <gnt.h>
#include <gntbutton.h>
#include <gntcheckbox.h>
#include <gntcombobox.h>
#include <gntentry.h>
#include <gntlabel.h>
#include <gntline.h>
#include <gntmenu.h>
#include <gnttextview.h>
#include <gnttree.h>
#include <gntwindow.h>

#include <parted/parted.h>

#define _(X) X  /* XXX: For now */

struct {
	GntWindow *window;
	GntTree *devlist;
	GntTree *partlist;
	GntTextView *info;
	GntMenu *menu;

	GHashTable *disks;
} mw; /* Main window */

enum {
	DSK_NUMBER = 0,
	DSK_START,
	DSK_END,
	DSK_SIZE,
	DSK_TYPE,
	DSK_FLAGS,
	DSK_ALL
};

/**
 * Stuff copied from parted.c:do_print -- sadrul
 */
static void
selection_changed(GntTree *tree, gpointer old, gpointer now, gpointer null)
{
	PedDisk* disk;
	PedPartition *part, *ext;
	PedDevice *dev = now;
	int has_extended;
	int has_name;
	char *str;
	char* transport[13] = {"unknown", "scsi", "ide", "dac960",
	                       "cpqarray", "file", "ataraid", "i2o",
	                       "ubd", "dasd", "viodasd", "sx8", "dm"};

	gnt_tree_remove_all(mw.partlist);
	gnt_widget_draw(GNT_WIDGET(mw.partlist));

	gnt_text_view_clear(mw.info);

#define STUFF(tag, string) \
	gnt_text_view_append_text_with_flags(mw.info, tag, \
			GNT_TEXT_FLAG_BOLD); \
	gnt_text_view_append_text_with_flags(mw.info, string, \
			GNT_TEXT_FLAG_NORMAL); \
	g_free(string);

	STUFF(_("Disk: "), g_strdup_printf("%s\n", dev->path));
	STUFF(_("Model: "), g_strdup_printf("%s (%s)\n", dev->model, transport[dev->type]));
	STUFF(_("Sector size (log/phy): "), g_strdup_printf("%lldB/%lldB\n", dev->sector_size, dev->phys_sector_size));

	/* XXX: `parted' creates and frees a PedDisk for every 'print' command.
	 * I am creating them once and storing them in a dev -> disk hashtable.
	 * Can this cause any problem?
	 */
	disk = g_hash_table_lookup(mw.disks, dev);
	if (!disk) {
		disk = ped_disk_new(dev);
		if (disk == NULL) {
			gnt_text_view_scroll(mw.info, 0);
			return;
		}
		g_hash_table_replace(mw.disks, dev, disk);
	}

	STUFF(_("Partition Table: "), g_strdup_printf("%s\n", disk->type->name));
	STUFF(_("Primary: "), g_strdup_printf("%d (Max: %d)\n",
			ped_disk_get_primary_partition_count(disk),
			ped_disk_get_max_primary_partition_count(disk)));

	gnt_text_view_scroll(mw.info, 0);

	has_extended = ped_disk_type_check_feature(disk->type,
									 PED_DISK_TYPE_EXTENDED);
	has_name = ped_disk_type_check_feature(disk->type,
									 PED_DISK_TYPE_PARTITION_NAME);

	ext = NULL;
	for (part = ped_disk_next_partition(disk, NULL); part;
			part = ped_disk_next_partition(disk, part)) {
		GList *list = NULL;
		char *str;

		if (part->type & PED_PARTITION_METADATA)
			continue;

		/* Number */
		str = (part->num >= 0) ? g_strdup_printf("%d", part->num) : g_strdup("");
		list = g_list_append(list, str);

		/* Start */
		str = ped_unit_format(dev, part->geom.start);
		list = g_list_append(list, g_strdup(str));
		ped_free(str);

		/* End */
		str = ped_unit_format_byte(dev, (part->geom.end + 1) * dev->sector_size - 1);
		list = g_list_append(list, g_strdup(str));
		ped_free(str);

		/* Size */
		if (ped_unit_get_default() == PED_UNIT_CHS)
			list = g_list_append(list, g_strdup(""));
		else {
			str = ped_unit_format(dev, part->geom.length);
			list = g_list_append(list, g_strdup(str));
			ped_free(str);
		}

		/* Type */
		if (part->type == PED_PARTITION_EXTENDED)
			str = g_strdup(_("extended"));
		else
			str = g_strdup(part->fs_type ? part->fs_type->name : "");
		list = g_list_append(list, str);

		/* Flags */
		list = g_list_append(list, g_strdup(""));  /* XXX: for now */

		gnt_tree_add_row_last(mw.partlist, part,
				gnt_tree_create_row_from_list(mw.partlist, list),
				(part->type == PED_PARTITION_LOGICAL) ? ext : NULL);

		g_list_foreach(list, (GFunc)g_free, NULL);
		g_list_free(list);
		if (part->type == PED_PARTITION_EXTENDED)
			ext = part;
	}
}

static const char*
s_unit_get_name(PedUnit unit)
{
	switch (unit) {
		case PED_UNIT_SECTOR:
			return _("Sector");
		case PED_UNIT_BYTE:
			return _("Byte");
		case PED_UNIT_KILOBYTE:
			return _("KiloByte");
		case PED_UNIT_MEGABYTE:
			return _("MegaByte");
		case PED_UNIT_GIGABYTE:
			return _("GigaByte");
		case PED_UNIT_TERABYTE:
			return _("TeraByte");
		case PED_UNIT_COMPACT:
			return _("Compact");
		case PED_UNIT_CYLINDER:
			return _("Cylinder");
		case PED_UNIT_CHS:
			return _("CHS");
		case PED_UNIT_PERCENT:
			return _("Percent");
		case PED_UNIT_KIBIBYTE:
			return _("KibiByte");
		case PED_UNIT_MEBIBYTE:
			return _("MebiByte");
		case PED_UNIT_GIBIBYTE:
			return _("GibiByte");
		case PED_UNIT_TEBIBYTE:
			return _("TebiByte");
	}
	return _("Unknown");
}

static void
do_create()
{
	/* XXX: Should more than one 'create' window be allowed at the same time? */
	GntWidget *win, *combo, *hbox, *vbox, *button, *entry;
	PedFileSystemType *type;
	PedUnit unit;

	win = gnt_vwindow_new(FALSE);
	gnt_box_set_title(GNT_BOX(win), _("Create Partition"));
	gnt_box_set_alignment(GNT_BOX(win), GNT_ALIGN_MID);
	gnt_box_set_pad(GNT_BOX(win), 0);

	hbox = gnt_hbox_new(TRUE);
	gnt_box_add_widget(GNT_BOX(win), hbox);
	gnt_box_set_fill(GNT_BOX(hbox), FALSE);
	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Create as: ")));
	combo = gnt_combo_box_new();
	gnt_box_add_widget(GNT_BOX(hbox), combo);
	gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "primary", _("Primary"));
	gnt_combo_box_add_data(GNT_COMBO_BOX(combo), "extended", _("Extended"));

	hbox = gnt_hbox_new(TRUE);
	gnt_box_add_widget(GNT_BOX(win), hbox);
	gnt_box_set_fill(GNT_BOX(hbox), FALSE);
	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Partition Type: ")));
	combo = gnt_combo_box_new();
	gnt_box_add_widget(GNT_BOX(hbox), combo);
	type = NULL;
	while ((type = ped_file_system_type_get_next(type)) != NULL) {
		gnt_combo_box_add_data(GNT_COMBO_BOX(combo), type, type->name);
	}

	hbox = gnt_hbox_new(TRUE);
	gnt_box_add_widget(GNT_BOX(win), hbox);
	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Label: ")));
	gnt_box_add_widget(GNT_BOX(hbox), gnt_entry_new(NULL));

	gnt_box_add_widget(GNT_BOX(win), gnt_label_new(""));

	hbox = gnt_hbox_new(TRUE);
	gnt_box_add_widget(GNT_BOX(win), hbox);
	gnt_box_set_fill(GNT_BOX(hbox), FALSE);
	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Size: ")));
	gnt_box_add_widget(GNT_BOX(hbox), entry = gnt_entry_new("0"));
	gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT);

	hbox = gnt_hbox_new(TRUE);
	gnt_box_add_widget(GNT_BOX(win), hbox);
	gnt_box_set_fill(GNT_BOX(hbox), FALSE);
	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Unit: ")));
	combo = gnt_combo_box_new();
	/* For the known units, the keys are the (enum-value + 1) because it starts from 0, and the key
	 * in a GntTree cannot be NULL/0 */
	for (unit = PED_UNIT_FIRST; unit <= PED_UNIT_LAST; unit++)
		gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(unit + 1), s_unit_get_name(unit));
	gnt_box_add_widget(GNT_BOX(hbox), combo);

	gnt_box_add_widget(GNT_BOX(win), gnt_check_box_new(_("Beginning of unallocated space")));
	gnt_box_add_widget(GNT_BOX(win), gnt_check_box_new(_("End of unallocated space")));

	hbox = gnt_hbox_new(FALSE);
	gnt_box_add_widget(GNT_BOX(win), hbox);
	button = gnt_button_new(_("OK"));
	gnt_box_add_widget(GNT_BOX(hbox), button);
	button = gnt_button_new(_("Cancel"));
	gnt_box_add_widget(GNT_BOX(hbox), button);

	gnt_widget_show(win);
}

static void
main_init()
{
	GntWidget *window;
	GntWidget *button;
	GntWidget *tree;
	GntWidget *box, *box2;
	GntWidget *tv;
	GList *cols;
	int widths[] = {8, 10, 10, 9, 10, 10};  /* XXX: ew */
	int i;
	struct {
		const char *name;
		void (*fn)();
	} actions[] = {
		/*{_("Property"), NULL},*/
		{_("Create"), do_create},
		{_("Format"), NULL},
		{_("Resize"), NULL},
		{_("Move"), NULL},
		{_("Delete"), NULL},
		{NULL, NULL}
	};

	window = gnt_vwindow_new(FALSE);
	gnt_box_set_title(GNT_BOX(window), _("GNT-Parted"));
	gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
	gnt_box_set_pad(GNT_BOX(window), 0);
	mw.window = GNT_WINDOW(window);

	/* Dev-list and info-box */
	box = gnt_hbox_new(FALSE);
	gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_TOP);
	gnt_box_set_fill(GNT_BOX(box), TRUE);
	gnt_box_add_widget(GNT_BOX(window), box);

		/* device list */
	box2 = gnt_vbox_new(FALSE);
	gnt_box_set_pad(GNT_BOX(box2), 0);
	tree = gnt_tree_new();
	GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER);
	gnt_tree_set_col_width(GNT_TREE(tree), 0, 20);
	mw.devlist = GNT_TREE(tree);
	gnt_box_add_widget(GNT_BOX(box2), gnt_label_new_with_format(_("Device List"), GNT_TEXT_FLAG_BOLD));
	gnt_box_add_widget(GNT_BOX(box2), tree);

	gnt_box_add_widget(GNT_BOX(box), box2);
	g_signal_connect(G_OBJECT(tree), "selection_changed",
		G_CALLBACK(selection_changed), NULL);

		/* info-box */
	tv = gnt_text_view_new();
	gnt_box_add_widget(GNT_BOX(box), tv);
	gnt_widget_set_size(tv, 50, -1);
	mw.info = GNT_TEXT_VIEW(tv);

	/* Partition list */
	tree = gnt_tree_new_with_columns(DSK_ALL);
	GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER);
	gnt_tree_set_col_width(GNT_TREE(tree), 0, 40);
	mw.partlist = GNT_TREE(tree);

	gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
	gnt_tree_set_column_titles(GNT_TREE(tree),
					_("Number"), _("Start"), _("End"), _("Size"),
	                _("Type"), _("Flags"));
	for (i = 0; i < DSK_ALL; i++)
		gnt_tree_set_col_width(GNT_TREE(tree), i, widths[i]);
	gnt_box_add_widget(GNT_BOX(window), tree);

	gnt_box_add_widget(GNT_BOX(window), gnt_hline_new());

	/* List of buttons */
	box = gnt_hbox_new(FALSE);
	gnt_box_add_widget(GNT_BOX(window), box);

	for (i = 0; actions[i].name; i++) {
		button = gnt_button_new(actions[i].name);
		gnt_box_add_widget(GNT_BOX(box), button);
		if (actions[i].fn)
			g_signal_connect(G_OBJECT(button), "activate",
				G_CALLBACK(actions[i].fn), NULL);
	}

	mw.disks = g_hash_table_new_full(g_direct_hash, g_direct_equal,
					NULL, (GDestroyNotify)ped_disk_destroy);

	gnt_widget_show(window);
}

int main()
{
	PedDevice *dev = NULL;
	int count;

	freopen(".error", "w", stderr);

	gnt_init();

	main_init();

	count = 0;
	ped_device_probe_all();
	while ((dev = ped_device_get_next(dev)) != NULL) {
		char *size = ped_unit_format_byte(dev, dev->length * dev->sector_size - 1);
		char *str = g_strdup_printf("%s (%s)", dev->path, size ? size : "");
		gnt_tree_add_row_last(mw.devlist, dev,
			gnt_tree_create_row(mw.devlist, str), NULL);
		g_free(str);
		ped_free(size);
		if (count == 0) {
			gnt_tree_set_selected(mw.devlist, dev);
			selection_changed(mw.devlist, NULL, dev, NULL);
		}
		count++;
	}
	gnt_main();

	gnt_quit();

	return 0;
}

